package cn.tedu.service;

import cn.tedu.lucene.IKAnalyzer6x;
import com.jt.common.pojo.Product;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.search.*;
import org.apache.lucene.store.FSDirectory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class IndexService {
    public void addIndex(String indexName) {
        // 副本分片，做高可用
        // 读取数据源 String模拟
        // 商品数据
        Product p1 = new Product();
        p1.setProductId("1");
        p1.setProductCategory("手机");
        p1.setProductDescription("3亿像素高清摄影，照亮景色的美");
        p1.setProductName("达内PN3 pro手机");
        p1.setProductNum(500);

        Product p2 = new Product();
        p2.setProductId("2");
        p2.setProductCategory("电脑");
        p2.setProductDescription("游戏发烧的选择，泰坦2080TI");
        p2.setProductName("达内杀手3000");
        p2.setProductNum(200);

        // 准备索引文件的输出目录
        try {
            Path path = Paths.get("C:/tedu/practice/java_ee/easymallparent/ik/" + indexName);
            FSDirectory dir = FSDirectory.open(path);
            // 给writter输出流配置一个配置对象
            IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer6x());
            // 定义创建索引的模式 追加 或 覆盖
            // create: 覆盖，每次执行都会对已有的同名目录做覆盖
            // append: 追加，同名文件夹存在，会对数据追加
            // create_or_append: 有则追加，无则创建
            config.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
            // 创建输出流对象
            IndexWriter writer = new IndexWriter(dir, config);
            // 封装document 从两个原数据p1,p2封装两个索引需要的document数据
            // document的数据结构需要和原数据一致，自定义document中的属性
            // 属性分为两大类，一类字符串类，一类数字类
            Document doc1 = new Document();
            Document doc2 = new Document();
            // TextField StringField存储字符串数据
            // name: 自定义属性名称
            // value: 属性值
            // store: 表示是否存储在索引中
            doc1.add(new TextField("productId", p1.getProductId(), Field.Store.YES));
            doc1.add(new TextField("productCategory", p1.getProductCategory(), Field.Store.YES));
            doc1.add(new TextField("productDescription", p1.getProductDescription(), Field.Store.YES));
            doc1.add(new TextField("productName", p1.getProductName(), Field.Store.YES));
            doc1.add(new IntPoint("num", p1.getProductNum()));
            doc1.add(new StringField("num", p1.getProductNum().toString(), Field.Store.YES));

            doc2.add(new TextField("productId", p2.getProductId(), Field.Store.YES));
            doc2.add(new TextField("productCategory", p2.getProductCategory(), Field.Store.YES));
            doc2.add(new StringField("productDescription", p2.getProductDescription(), Field.Store.YES));
            doc2.add(new TextField("productName", p2.getProductName(), Field.Store.NO));
            doc2.add(new IntPoint("num", p2.getProductNum()));
            doc2.add(new StringField("num", p2.getProductNum().toString(), Field.Store.YES));

            // 将document封装到writer
            writer.addDocument(doc1);
            writer.addDocument(doc2);

            // 创建索引
            writer.commit();// 文件夹出现默认空环境结构，没有数据
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public String search(String indexName, String fieldName, String text) {
        String result = "";
        // 指向搜索数据的索引文件
        Path path = Paths.get("C:/tedu/practice/java_ee/easymallparent/ik/" + indexName);
        try {
            FSDirectory dir = FSDirectory.open(path);
            // 拿到搜索对象
            IndexReader reader = DirectoryReader.open(dir);
            IndexSearcher searcher = new IndexSearcher(reader);
            // 构造查询条件
            // 多个布尔子条件查询
            Query query1 = new TermQuery(new Term(fieldName, text));
            Query query2 = new TermQuery(new Term("productCategory", text));
            // 子查询封装成布尔的子条件
            // Occur发生逻辑值
            // must: 查询结果一定属于该子条件的一部分
            // must_not: 查询结果一定不属于该子条件
            // should: 查询结果可以包含，也可以不包含该条件，must同时使用，以must为准
            // filter: must相同的效果，但是使用filter的条件对应的结果，没有评分
            BooleanClause bc1 = new BooleanClause(query1, BooleanClause.Occur.MUST);
            BooleanClause bc2 = new BooleanClause(query2, BooleanClause.Occur.MUST);
            // 利用两个子条件封装布尔
            Query query = new BooleanQuery.Builder().add(bc1).add(bc2).build();
            // 遍历循环
            TopDocs topDocs = searcher.search(query, 10);
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;
            for (ScoreDoc scoreDoc : scoreDocs) {
                System.out.println("documentId: " + scoreDoc.doc);
                // 获取document对象
                Document doc = searcher.doc(scoreDoc.doc);
                System.out.println("productName" + doc.get("productName"));
                System.out.println("productCategory" + doc.get("productCategory"));
                System.out.println("productDescription" + doc.get("productDescription"));
                System.out.println("num" + doc.get("num"));
                result = result + "/" + doc.get("productName") + "/" + doc.get("productCategory");
            }
        } catch (IOException ioException) {
            ioException.printStackTrace();
        } finally {
            return result;
        }
    }
}
